/*
 * StepGenerate.c
 *
 *  Created on: 2012-8-16
 *      Author: zhangchao
 */
#include <Game.h>
#include <Chess.h>
#include <StepGenerate.h>

#define DIFF_SIDE_CHESS(chess,side) chess>>7!=side
#define CAN_PLACE_CHESS(board,indexX,indexY,side) (board[indexX][indexY] == 0|| DIFF_SIDE_CHESS(board[indexX][indexY],side))
#define IS_XIANG_NOT_CROSS(indexY,side) ((side==0&&indexY<5)||(side==1&&indexY>4))
#define GET_NEW_POS_CHESS_BY_STEP(board,step) board[(step>>4|15)][(step|15)]

int* getAllPossibleStep(char board[][], int *stepCnt) {

	int steps[100];
	*stepCnt = 100;
	int currentIndex = 0;
	int indexX = 0;
	int indexY = 0;

	for (; indexX <= INDEX_X_MAX; indexX++)
		for (; indexY <= INDEX_Y_MAX; indexY++) {
			if (board[indexX][indexY] != 0) {
				calStep(board, indexX, indexY, &currentIndex, stepCnt, steps);
			}
		}

	*stepCnt = currentIndex + 1;
	return steps;
}

void addStepToArray(int steps[], int *arrayCnt, int oldIndexX, int oldIndexY,
		int indexX, int indexY, int *currentIndex) {

	int i;

	if (*currentIndex == *arrayCnt - 1) {
		int tmp[*arrayCnt + 20];
		for (i = 0; i < arrayCnt; i++) {
			tmp[i] = steps[i];
		}
		steps = tmp;
		*arrayCnt = *arrayCnt + 20;
	}

	steps[*currentIndex] = makeStepIntByParam(oldIndexX, oldIndexY, indexX,
			indexY);
	(*currentIndex)++;
}

void calStep(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[]) {
	char chess = board[oldIndexX][oldIndexY];
	char type = (chess >> 4) | 7;
	switch (type) {
	case CHESS_BIN:
		calStepBin(board, oldIndexX, oldIndexY, currentIndex, arrayCnt, steps);
		break;
	case CHESS_PAO:
		calStepPao(board, oldIndexX, oldIndexY, currentIndex, arrayCnt, steps);
		break;
	case CHESS_JU:
		calStepJu(board, oldIndexX, oldIndexY, currentIndex, arrayCnt, steps);
		break;
	case CHESS_MA:
		calStepMa(board, oldIndexX, oldIndexY, currentIndex, arrayCnt, steps,false);
		break;
	case CHESS_XIANG:
		calStepXiang(board, oldIndexX, oldIndexY, currentIndex, arrayCnt,
				steps);
		break;
	case CHESS_SHUAI:
		calStepShuai(board, oldIndexX, oldIndexY, currentIndex, arrayCnt,
				steps);
		break;
	default:
		calStepShuai(board, oldIndexX, oldIndexY, currentIndex, arrayCnt,
				steps);
		break;
	}
}

void calStepBin(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[]) {

	int indexX;
	int indexY;
	char side = board[oldIndexX][oldIndexY] >> 7;

	/*上1，不是最上边*/
	if (oldIndexY < INDEX_Y_MAX && IS_OWN_CHESS(board[oldIndexX][oldIndexY])) {
		indexX = oldIndexX;
		indexY = oldIndexY + 1;
		/* 敌方可吃子 */
		if (DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
			addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX,
					indexY, currentIndex);
		}
	}
	/*下1，不是最上边*/
	if (oldIndexY < INDEX_Y_MAX && !IS_OWN_CHESS(board[oldIndexX][oldIndexY])) {
		indexX = oldIndexX;
		indexY = oldIndexY - 1;
		/* 敌方可吃子 */
		if (DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
			addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX,
					indexY, currentIndex);
		}
	}

	/*未过河*/
	if ((oldIndexY < 5 && IS_OWN_CHESS(board[oldIndexX][oldIndexY]))
			|| (oldIndexY > 4 && !IS_OWN_CHESS(board[oldIndexX][oldIndexY]))) {
		return;
	}

	/* 左1,不是最左边 */
	if (oldIndexX > 0) {
		indexX = oldIndexX - 1;
		indexY = oldIndexY;
		/* 敌方可吃子 */
		if (DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
			addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX,
					indexY, currentIndex);
		}
	}

	/* 右1,不是最右边 */
	if (oldIndexX < INDEX_X_MAX) {
		indexX = oldIndexX + 1;
		indexY = oldIndexY;
		/* 敌方可吃子 */
		if (DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
			addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX,
					indexY, currentIndex);
		}

	}
}

void calStepPao(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[]) {

	int indexX = oldIndexX;
	int indexY = oldIndexY;

	/* X轴的棋步 */

	/* 左 */
	indexX = oldIndexX - 1;
	while (indexX > 0 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexX--;
	}

	/* 右 */
	indexX = oldIndexX + 1;
	while (indexX < INDEX_X_MAX + 1 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexX++;
	}

	/* Y轴的棋步 */

	/* 上 */
	indexX = oldIndexX;
	indexY = oldIndexY + 1;

	while (indexY < INDEX_Y_MAX + 1 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexY++;
	}

	/* 下 */
	indexX = oldIndexX;
	indexY = oldIndexY - 1;

	while (indexY > 0 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexY--;
	}
}

void calStepJu(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[]) {
	int indexX = oldIndexX;
	int indexY = oldIndexY;
	char side = board[oldIndexX][oldIndexY] >> 7;

	/* X轴的棋步 */

	/* 左 */
	indexX = oldIndexX - 1;
	while (indexX > 0 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexX--;
	}

	if (indexX > 0 && DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	/* 右 */
	indexX = oldIndexX + 1;
	while (indexX < INDEX_X_MAX + 1 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexX++;
	}

	if (indexX < INDEX_X_MAX + 1 && DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	/* Y轴的棋步 */

	/* 上 */
	indexX = oldIndexX;
	indexY = oldIndexY + 1;

	while (indexY < INDEX_Y_MAX + 1 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexY++;
	}

	if (indexY < INDEX_Y_MAX + 1 && DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	/* 下 */
	indexX = oldIndexX;
	indexY = oldIndexY - 1;

	while (indexY > 0 && board[indexX][indexY] != 0) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
		indexY--;
	}

	if (indexY > 0 && DIFF_SIDE_CHESS(board[indexX][indexY],side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}
}

void calStepMa(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[],bool isCalBeKilled) {
	int indexX = oldIndexX;
	int indexY = oldIndexY;
	char side = board[oldIndexX][oldIndexY] >> 7;

	/* 左上 */
	indexX = oldIndexX - 1;
	indexY = oldIndexY + 2;

	if (isRightStep(indexX, indexY) && board[oldIndexX-isCalBeKilled?1:0][oldIndexY + 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX - 2;
	indexY = oldIndexY + 1;

	if (isRightStep(indexX, indexY) && board[oldIndexX - 1][oldIndexY+isCalBeKilled?1:0] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	/* 左下 */
	indexX = oldIndexX - 1;
	indexY = oldIndexY - 2;

	if (isRightStep(indexX, indexY) && board[oldIndexX-isCalBeKilled?1:0][oldIndexY - 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX - 2;
	indexY = oldIndexY - 1;

	if (isRightStep(indexX, indexY) && board[oldIndexX - 1][oldIndexY-isCalBeKilled?1:0] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	/* 右上 */
	indexX = oldIndexX + 1;
	indexY = oldIndexY + 2;

	if (isRightStep(indexX, indexY) && board[oldIndexX+isCalBeKilled?1:0][oldIndexY + 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX + 2;
	indexY = oldIndexY + 1;

	if (isRightStep(indexX, indexY) && board[oldIndexX + 1][oldIndexY+isCalBeKilled?1:0] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	/* 右下 */
	indexX = oldIndexX + 1;
	indexY = oldIndexY - 2;

	if (isRightStep(indexX, indexY) && board[oldIndexX+isCalBeKilled?1:0][oldIndexY - 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX + 2;
	indexY = oldIndexY - 1;

	if (isRightStep(indexX, indexY) && board[oldIndexX + 1][oldIndexY-isCalBeKilled?1:0] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

}

void calStepXiang(char board[][], int oldIndexX, int oldIndexY,
		int *currentIndex, int *arrayCnt, int steps[]) {
	int indexX = oldIndexX;
	int indexY = oldIndexY;
	char side = board[oldIndexX][oldIndexY] >> 7;

	indexX = oldIndexX - 2;
	indexY = oldIndexY - 2;

	if (isRightStep(indexX,
			indexY) && IS_XIANG_NOT_CROSS(indexY,side)
			&& board[oldIndexX - 1][oldIndexY - 1] == 0 && CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,currentIndex);
}

	indexX = oldIndexX - 2;
	indexY = oldIndexY + 2;

	if (isRightStep(indexX, indexY) &&IS_XIANG_NOT_CROSS(indexY,side)
	&& board[oldIndexX - 1][oldIndexY + 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX + 2;
	indexY = oldIndexY - 2;

	if (isRightStep(indexX,
			indexY) &&IS_XIANG_NOT_CROSS(indexY,side)&& board[oldIndexX + 1][oldIndexY - 1] == 0
			&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

	indexX = oldIndexX + 2;
	indexY = oldIndexY + 2;

	if (isRightStep(indexX, indexY) &&IS_XIANG_NOT_CROSS(indexY,side)
	&& board[oldIndexX + 1][oldIndexY + 1] == 0
	&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
			currentIndex);
}

}

void calStepShi(char board[][], int oldIndexX, int oldIndexY, int *currentIndex,
		int *arrayCnt, int steps[]) {
	char side = board[oldIndexX][oldIndexY] >> 7;
	int indexX = oldIndexX - 1;
	int indexY = oldIndexY - 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX + 1;
	indexY = oldIndexY - 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX - 1;
	indexY = oldIndexY + 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX + 1;
	indexY = oldIndexY + 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}
}

bool isRightStepShiAndShuai(int indexX, int indexY) {
	if ((indexX > 2 && indexX < 6 && indexY > -1 && indexY < 3)
			|| (indexX > 2 && indexX < 6 && indexY > 6 && indexY < 10)) {
		return true;
	}

	return false;
}

void calStepShuai(char board[][], int oldIndexX, int oldIndexY,
		int *currentIndex, int *arrayCnt, int steps[]) {
	char side = board[oldIndexX][oldIndexY] >> 7;
	int indexX = oldIndexX - 1;
	int indexY = oldIndexY;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX + 1;
	indexY = oldIndexY;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX;
	indexY = oldIndexY - 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	indexX = oldIndexX;
	indexY = oldIndexY + 1;

	if (isRightStepShiAndShuai(indexX,
			indexY)&& CAN_PLACE_CHESS(board,indexX,indexY,side)) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

	/* kill */
	indexX = oldIndexX;
	indexY = oldIndexY + (side == 0) ? 1 : -1;
	while (board[indexX][indexY] == 0) {
		indexY = indexY + (side == 0) ? 1 : -1;
	}

	char type;
	type = (board[indexX][indexY] >> 4) | 7;
	if (type == CHESS_SHUAI) {
		addStepToArray(steps, arrayCnt, oldIndexX, oldIndexY, indexX, indexY,
				currentIndex);
	}

}

bool isRightStep(int indexX, int indexY) {
	if (indexX < 0 || indexX > INDEX_X_MAX || indexY < 0
			|| indexY > INDEX_Y_MAX) {
		return false;
	}

	return true;
}

bool canBeFinished(char board[][], char side) {
	int oldIndexX, oldIndexY;
	int indexX, indexY;
	char chessShuai = (side << 7) + (CHESS_SHUAI << 4);
	int cnt = 20;
	int steps[cnt];
	int currentIndex = 0;
	int i;
	char chessType;
	char chessSide;

	for (oldIndexX = 0; oldIndexX <= INDEX_X_MAX; oldIndexX++)
		for (oldIndexY = 0; oldIndexY < INDEX_Y_MAX; oldIndexY++) {
			if (board[oldIndexX][oldIndexY] == chessShuai) {
				break;
			}
		}

	calStepBin(board, oldIndexX, oldIndexY, &currentIndex, cnt, steps);

	for (i = 0; i <= currentIndex; i++) {
		getChessTypeAndSide(GET_NEW_POS_CHESS_BY_STEP(board,steps[i]),&chessType,&chessSide);
		if(chessSide!=side&&chessType==CHESS_BIN) {
			return true;
		}

	}

	calStepPao(board, oldIndexX, oldIndexY, &currentIndex, cnt, steps);

	for (i = 0; i <= currentIndex; i++) {
		getChessTypeAndSide(GET_NEW_POS_CHESS_BY_STEP(board,steps[i]),&chessType,&chessSide);
		if(chessSide!=side&&chessType==CHESS_PAO) {
			return true;
		}

	}

	calStepMa(board, oldIndexX, oldIndexY, &currentIndex, cnt, steps, true);

	for (i = 0; i <= currentIndex; i++) {
		getChessTypeAndSide(GET_NEW_POS_CHESS_BY_STEP(board,steps[i]),&chessType,&chessSide);
		if(chessSide!=side&&chessType==CHESS_MA) {
			return true;
		}

	}
	calStepJu(board, oldIndexX, oldIndexY, &currentIndex, cnt, steps);

	for (i = 0; i <= currentIndex; i++) {
		getChessTypeAndSide(GET_NEW_POS_CHESS_BY_STEP(board,steps[i]),&chessType,&chessSide);
		if(chessSide!=side&&chessType==CHESS_JU) {
			return true;
		}

	}
	calStepShuai(board, oldIndexX, oldIndexY, &currentIndex, cnt, steps);

	for (i = 0; i <= currentIndex; i++) {
		getChessTypeAndSide(GET_NEW_POS_CHESS_BY_STEP(board,steps[i]),&chessType,&chessSide);
		if(chessSide!=side&&chessType==CHESS_SHUAI) {
			return true;
		}

	}

	return false;
}
